﻿using Caviar.Core.Interface;
using Caviar.SharedKernel.Common.Extensions;
using Caviar.SharedKernel.Common.Helpers;
using Caviar.SharedKernel.Entities.IM;
using Microsoft.AspNetCore.Http;
using StackExchange.Redis;
using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;

namespace Caviar.Core.Services.IMServices
{
    public class IMUserManager :  DbServices
    {
        private readonly IAppDbContext _appDbContext;
        private readonly IHttpContextAccessor _contextAccessor;
        private readonly IDatabase _redis;
        public IMUserManager(
            IAppDbContext dbContext,
            RedisHelper client,
            IHttpContextAccessor contextAccessor) : base(dbContext)
        {
            _appDbContext = dbContext;
            _redis = client.GetDatabase();
            _contextAccessor = contextAccessor;
        }

        /// <summary>
        /// 缓存数据
        /// </summary>
        /// <returns></returns>
        public async Task SaveAsync(string key, Object values, DateTime? dateTime, bool isToJson = true)
        {
            JwtConfig jwtConfig = new JwtConfig();
            if (isToJson)
            {
                await _redis.StringSetAsync(key, values.ToJson());
            }
            else
            {
                await _redis.StringSetAsync(key, values.ToString());
            }
            
            if (dateTime != null)
            {
                await _redis.KeyExpireAsync(key, dateTime?.AddMinutes(jwtConfig.Expires));
            }          
        }

        /// <summary>
        /// 删除登录者信息
        /// </summary>
        /// <returns></returns>
        public async Task DeleteAsync(string token) 
        {
            await _redis.StringGetDeleteAsync(token);
        }

        /// <summary>
        /// 获取用户信息
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public async Task<User> GetUserAsync(string token)
        {
            var value = await _redis.StringGetAsync(token);
            if (value.IsNullOrEmpty)
                throw new Exception("请重新登录");

            return value.ToString().ToObject<User>();
        }

        /// <summary>
        /// 获取登录用户信息
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public async Task<User> GetCurrentUserAsync()
        {
            string token = _contextAccessor.HttpContext.Request.Headers["Authorization"].ToString();
            var value = await _redis.StringGetAsync(token);
            if (value.IsNullOrEmpty)
                throw new Exception("请重新登录");

            return value.ToString().ToObject<User>();
        }

        /// <summary>
        /// 获取登录用户Id
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public int GetCurrentUserId()
        {
            string token = _contextAccessor.HttpContext.Request.Headers["Authorization"].ToString();
            var value = _redis.StringGet(token);
            if (value.IsNullOrEmpty)
                throw new Exception("请重新登录");

            return value.ToString().ToObject<User>().Id;
        }

        public string Create(Claim[] claims, DateTime dateTime)
        {
            JwtConfig jwtConfig = new JwtConfig();
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtConfig.SecurityKey));
            var signingCredentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            var timestamp = DateTime.Now.AddMinutes(jwtConfig.Expires + jwtConfig.RefreshExpires).ToTimestamp().ToString();
            claims = claims.Append(new Claim(ClaimAttributes.RefreshExpires, timestamp)).ToArray();

            var token = new JwtSecurityToken(
                issuer: jwtConfig.Issuer,
                audience: jwtConfig.Audience,
                claims: claims,
                notBefore: dateTime,
                expires: dateTime.AddMinutes(jwtConfig.Expires),
                signingCredentials: signingCredentials
            );
            return new JwtSecurityTokenHandler().WriteToken(token);
        }

        public Claim[] Decode(string jwtToken)
        {
            var jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
            var jwtSecurityToken = jwtSecurityTokenHandler.ReadJwtToken(jwtToken);
            return jwtSecurityToken?.Claims?.ToArray();
        }

        /// <summary>
        /// Jwt配置
        /// </summary>
        public class JwtConfig
        {
            /// <summary>
            /// 发行者
            /// </summary>
            public string Issuer { get; set; } = "http://127.0.0.1:5555";

            /// <summary>
            /// 订阅者
            /// </summary>
            public string Audience { get; set; } = "http://127.0.0.1:5555";

            /// <summary>
            /// 密钥
            /// </summary>
            public string SecurityKey { get; set; } = "ertJKl#521*a@790asD&1#";

            /// <summary>
            /// 有效期(分钟)
            /// </summary>
            public int Expires { get; set; } = 120;

            /// <summary>
            /// 刷新有效期(分钟)
            /// </summary>
            public int RefreshExpires { get; set; } = 480;
        }
        /// <summary>
        /// Claim属性
        /// </summary>
        public static class ClaimAttributes
        {
            /// <summary>
            /// 用户Id
            /// </summary>
            public const string UserId = "id";

            /// <summary>
            /// 客户端ID
            /// </summary>
            public const string ClientId = "ci";

            /// <summary>
            /// 认证授权用户Id
            /// </summary>
            public const string IdentityServerUserId = "sub";

            /// <summary>
            /// 用户名
            /// </summary>
            public const string UserName = "na";

            /// <summary>
            /// 姓名
            /// </summary>
            public const string UserNickName = "nn";

            /// <summary>
            /// 头像
            /// </summary>
            public const string Avatar = "ar";

            /// <summary>
            /// 刷新有效期
            /// </summary>
            public const string RefreshExpires = "re";
        }
    }
}
